import { Injectable } from '@angular/core';
import { Hero } from './hero';
import { HttpClient, HttpHeaders } from '@angular/common/http';
// 实现返回数据异步
import { Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { MessageService } from './message.service';

@Injectable({
  providedIn: 'root'
})
export class HeroService {
  private heroesUrl = 'api/heroes';  // URL to web api
  // httpOptions保存请求中的特殊标头
  httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
  };
  constructor(
    private http: HttpClient,
    private messageService: MessageService
  ) { }

  // 返回一个hero的数组
  // Observable<Hero[]>返回值
  // getHeroes(): Observable<Hero[]> {
  //   // 给MessageService发送一条信息
  //   this.messageService.add('HeroService: fetched heroes')
  //   // of(HEROES) 会返回一个 Observable<Hero[]>，它会发出单个值，这个值就是这些模拟英雄的数组。
  //   return of(HEROES);;
  // }
  getHeroes (): Observable<Hero[]> {
    // 获取数据方法
    // GET返回无类型的JSON对象
    // <Hero[]>提供一个类型化的结果对象
    // catchError()操作员拦截Observable失败的操作。它将错误传递给错误处理程序，错误处理程序可以执行错误所需的操作
    return this.http.get<Hero[]>(this.heroesUrl)
               .pipe(
                  tap(_ => this.log('fetched heroes')),
                  catchError(this.handleError<Hero[]>('getHeroes', []))
               )
  }


  // getHero(id: number): Observable<Hero> {
  //   this.messageService.add(`HeroService: fetched hero id=${id}`);
  //   // find函数根据id找第一个匹配的值
  //   return of(HEROES.find(hero => hero.id === id))
  // }
  getHero(id: number): Observable<Hero> {
    const url = `${this.heroesUrl}/${id}`;
    return this.http.get<Hero>(url)
               .pipe(
                  tap(_ => this.log(`fetched hero id=${id}`)),
                  catchError(this.handleError<Hero>(`getHero id=${id}`))
               )
  }

  // 更新英雄信息
  updateHero (hero: Hero): Observable<any> {
    return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe(
      tap(_ => this.log(`updated hero id=${hero.id}`)),
      catchError(this.handleError<any>('updateHero'))
    );
  }

  // 添加英雄事件
  addHero (hero: Hero): Observable<Hero> {
    return this.http.post<Hero>(this.heroesUrl, hero, this.httpOptions).pipe(
      tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
      catchError(this.handleError<Hero>('addHero'))
    );
  }

  // 删除英雄事件
  deleteHero (hero: Hero | number): Observable<Hero> {
    const id = typeof hero === 'number' ? hero : hero.id;
    const url = `${this.heroesUrl}/${id}`;

    return this.http.delete<Hero>(url, this.httpOptions).pipe(
      tap(_ => this.log(`deleted hero id=${id}`)),
      catchError(this.handleError<Hero>('deleteHero'))
    );
  }

  // 搜索英雄
  searchHeroes(term: string): Observable<Hero[]> {
    if (!term.trim()) {
      // if not search term, return empty hero array.
      return of([]);
    }
    return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`).pipe(
      tap(_ => this.log(`found heroes matching "${term}"`)),
      catchError(this.handleError<Hero[]>('searchHeroes', []))
    );
  }

  private log(message: string) {
    this.messageService.add(`HeroService: ${message}`);
  }

  private handleError<T> (operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.error(error);
      this.log(`${operation} failed: ${error.message}`);
      return of(result as T);
    }
  }
}
